﻿using PMS.Domain.Seedwork;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using PMS.Domain.Events;
using PMS.Domain.Exceptions;

namespace PMS.Domain.AggregatesModel.ProjectAggregate
{
    /// <summary>
    /// 项目聚合根
    /// </summary>
    public class Project : Entity, IAggregateRoot
    {
        /// <summary>
        /// 项目名称
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// 项目描述
        /// </summary>
        public string Description { get; private set; }

        /// <summary>
        /// 创建人名
        /// </summary>
        public string CreateUserName { get; private set; }


        /// <summary>
        /// 创建人ID
        /// </summary>
        public int CreateUserId { get; private set; }

        /// <summary>
        /// 项目创建
        /// </summary>
        private DateTime CreatedTime { get; set; }

        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime StartTime { get; set; }

        /// <summary>
        /// 计划结束时间
        /// </summary>
        public DateTime PlanEndTime { get; set; }

        /// <summary>
        /// 实际结束时间
        /// </summary>
        public DateTime EndTime { get; set; }

        /// <summary>
        /// 项目阶段
        /// </summary>
        public ProjectStatus ProjectStatus { get; private set; }

        public int ProjectStatusId { get; private set; }

        /// <summary>
        /// 项目参与人
        /// </summary>
        private readonly List<ProjectContributor> _contributors;

        public IReadOnlyCollection<ProjectContributor> Contributors => _contributors;

        /// <summary>
        /// 项目所需清单
        /// </summary>
        private readonly List<ProjectConsumable> _projectConsumable;

        public IReadOnlyCollection<ProjectConsumable> ProjectConsumablies => _projectConsumable;


        /// <summary>
        /// 项目评审意见
        /// </summary>
        private readonly List<ProjectAuditAdvice> _auditAdvicies;

        public IReadOnlyCollection<ProjectAuditAdvice> AuditAdvicies => _auditAdvicies;


        public Project()
        {
            _auditAdvicies = new List<ProjectAuditAdvice>();
            _contributors = new List<ProjectContributor>();
            _projectConsumable = new List<ProjectConsumable>();
        }

        /// <summary>
        /// 创建项目
        /// </summary>
        /// <param name="name">项目名称</param>
        /// <param name="description">项目描述</param>
        /// <param name="createUserName">创建人姓名</param>
        /// <param name="createUserId">创建人ID</param>
        /// <param name="startTime">项目开始时间</param>
        /// <param name="planEndTime">项目结束时间</param>
        public Project(string name, string description, string createUserName, int createUserId, DateTime startTime, DateTime planEndTime)
        {
            Name = name;
            Description = description;
            CreateUserId = createUserId;
            CreateUserName = createUserName;
            CreatedTime = DateTime.Now;
            StartTime = startTime;
            PlanEndTime = planEndTime;
            ProjectStatusId = ProjectStatus.Create.Id;
            _auditAdvicies = new List<ProjectAuditAdvice>();
            _contributors = new List<ProjectContributor>();
            _projectConsumable = new List<ProjectConsumable>();
        }

        #region 领域方法

        /// <summary>
        /// 添加参与者
        /// </summary>
        /// <param name="contributors"></param>
        public void AddContributor(List<ProjectContributor> contributors)
        {
            foreach (var item in contributors)
            {
                //如果不存在就添加
                if (!_contributors.Any(b => b.UserId == item.UserId))
                {
                    _contributors.Add(item);

                    //加入项目事件通知
                    AddDomainEvent(new ProjectNotifactionDomianEvent
                    {
                        UserId = item.UserId,
                        Title = Name,
                        Message = $"{CreateUserName} 邀请你加入了 {Name} 项目"
                    });
                }
            }
        }

        /// <summary>
        /// 移除参与者
        /// </summary>
        /// <param name="contributors"></param>
        public  void RemoveContributor(List<ProjectContributor> contributors)
        {
            foreach (var item in contributors)
            {
                if (_contributors.Any(b => b.UserId == item.UserId))
                {
                    _contributors.Remove(item);
                    //退出项目事件通知
                    //加入项目事件通知
                    AddDomainEvent(new ProjectNotifactionDomianEvent
                    {
                        UserId = item.UserId,
                        Title = Name,
                        Message = $"你已经退出 {Name} 项目"
                    });
                }
            }
        }


        /// <summary>
        /// 添加项目清单
        /// </summary>
        /// <param name="projectConsumable"></param>
        public bool AddConsumable(List<ProjectConsumable> projectConsumablies)
        {
            //只有创建和审核阶段才能修改
            if(ProjectStatusId== ProjectStatus.Audit.Id || ProjectStatusId == ProjectStatus.Create.Id)
            {

                foreach (var item in projectConsumablies)
                {
                    if(!_projectConsumable.Any(b =>b.Name == item.Name && b.Provider ==item.Provider && b.Specification==item.Specification))
                    {
                        _projectConsumable.Add(item);
                    }
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 单条更新
        /// </summary>
        /// <param name="projectConsumable"></param>
        public bool UpdateConsumable(ProjectConsumable projectConsumable)
        {
            //只有创建和审核阶段才能修改
            if (ProjectStatusId == ProjectStatus.Audit.Id || ProjectStatusId == ProjectStatus.Create.Id)
            {
               if(!projectConsumable.IsTransient())
                {
                    var consumable = _projectConsumable.FirstOrDefault(b => b.Id == projectConsumable.Id);
                    consumable.Name = projectConsumable.Name;
                    consumable.Provider = projectConsumable.Provider;
                    consumable.Specification = projectConsumable.Specification;
                    consumable.RequiredNumber = projectConsumable.RequiredNumber;

                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 移除项目列表
        /// </summary>
        /// <param name="projectConsumablies"></param>
        /// <returns></returns>
        public bool RemoveConsumable(List<ProjectConsumable> projectConsumablies)
        {
            //只有创建和审核阶段才能修改
            if (ProjectStatusId == ProjectStatus.Audit.Id || ProjectStatusId == ProjectStatus.Create.Id)
            {
                foreach (var item in _projectConsumable)
                {
                    if(_projectConsumable.Any(b =>b.Id == item.Id))
                    {
                        _projectConsumable.Remove(item);
                    }

                }
                return true;
            }
            return false;
        }


        /// <summary>
        /// 添加审核建议，只有提交审核，才能添加意见
        /// </summary>
        /// <param name="userName">用户名称</param>
        /// <param name="advice">建议内容</param>
        public void AddAdvice(int userId, string userName, string message)
        {
            if (ProjectStatusId == ProjectStatus.Create.Id)
            {
                //只有在项目中的人才能添加意见
                if (_contributors.Any(b => b.UserId == userId))
                {
                    var advice = new ProjectAuditAdvice
                    {
                        UserId = userId,
                        Advice = message,
                        UserName = userName,
                        CreateTime = DateTime.Now
                    };
                    _auditAdvicies.Add(advice);

                    //添加消息通知
                    foreach (var item in _contributors)
                    {
                        //新增消息通知
                        AddDomainEvent(new ProjectNotifactionDomianEvent
                        {
                            Title = this.Name,
                            UserId = item.UserId,
                            Message = $"{userName} 添加了审核意见：{message} "
                        });
                    }
                }else
                {
                    throw new PMSDomainException("不是项目成员,无法添加审核意见");
                }
            }
            else
            {
                throw new PMSDomainException("项目还未提交审核，无法添加意见");
            }
        }

        /// <summary>
        /// 审核状态修改
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="auditStatue"></param>
        public void Audit(int userId, ProjectAuditStatus auditStatue)
        {
            if (ProjectStatusId == ProjectStatus.Audit.Id)
            {
                var contributor = _contributors.FirstOrDefault(b => b.UserId == userId);
                if (contributor != null)
                {
                    contributor.ProjectAuditStatusId = auditStatue.Id;

                    //通知所有人 审核消息内容
                    foreach (var item in _contributors)
                    {
                        //新增消息通知
                        AddDomainEvent(new ProjectNotifactionDomianEvent
                        {
                            UserId = item.UserId,
                            Title = this.Name,
                            Message = $"{contributor.UserName} 审核了 { Name } 状态： {auditStatue.Name} "
                        });
                    }
                }
                else
                {
                    throw new PMSDomainException($"当前项目状态{ProjectStatus.Name}，无法进行审核");
                }
            }
        }


        /// <summary>
        /// 项目状态变更为 审核状态 如果没有参与者，则无法通过
        /// </summary>
        /// <returns></returns>
        public bool StatusChangedToAudit()
        {
            ///如果没有参与者，不允许提交审核
            if (!_contributors.Any())
            {
                return false;
            }


            ProjectStatusId = ProjectStatus.Audit.Id;

            foreach (var item in _contributors)
            {                
                AddDomainEvent(new ProjectNotifactionDomianEvent
                {
                    Title = Name,
                    UserId = item.UserId,
                    Message = $"该项目 {Name} 需要你审核!"
                });
            }
            return true;
        }

        /// <summary>
        /// 项目状态变更为 实施阶段 如果有参与则未审核，则无法通过
        /// </summary>
        /// <returns></returns>
        public bool StatusChangedToExcute()
        {
            ///如果没有参与者，不允许提交审核
            if (!_contributors.Any(b => b.ProjectAuditStatus == ProjectAuditStatus.Approving || b.ProjectAuditStatus == ProjectAuditStatus.Refuse))
            {
                return false;
            }
            ProjectStatusId = ProjectStatus.Excute.Id;
            foreach (var item in _contributors)
            {               
                AddDomainEvent(new ProjectStatusChangedToExcuteDomainEvent
                {
                    Name = Name,
                    UserId = item.UserId,
                    Message = $"该项目 {Name} 已经进入实施阶段!",
                    Description = Description,
                    StartTime = StartTime,
                    PlanEndTime = PlanEndTime,
                    ProjectConsumablies = _projectConsumable
                });
            }
            return true;
        }

        /// <summary>
        /// 结束项目
        /// </summary>
        /// <returns></returns>
        public void StatusChangedToFinish()
        {
            EndTime = DateTime.Now;
            ProjectStatusId = ProjectStatus.Finish.Id;            
            //通知所有人 审核消息内容
            foreach (var item in _contributors)
            {
                //新增消息通知
                AddDomainEvent(new ProjectNotifactionDomianEvent
                {
                    UserId = item.UserId,
                    Title = this.Name,
                    Message = $"项目 {Name} 已经结束 "
                });
            }
        }



        #endregion


    }
}
